package tictactoe;

import java.awt.Point;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author buya
 */
public class Desk implements Cloneable {
    public static final int NO_WINNER = -1;
    public static final int CROSS = 1;
    public static final int CIRCLE = 0;

    private Set<Point> cross = new HashSet<Point>();
    private Set<Point> circle = new HashSet<Point>();
    private int width, height;

    public Desk(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }
    
    public Set<Point> getCrosses() {
        return Collections.unmodifiableSet(cross);
    }

    public Set<Point> getCircles() {
        return Collections.unmodifiableSet(circle);
    }

    public int getWinner() {
        if (checkCross()) {
            return CROSS;
        }
        if (checkCircle()) {
            return CIRCLE;
        }
        
        return NO_WINNER;
    }

    public boolean canPlace(Point where) {
        if (where.x < 0 || where.x >= width ||
                where.y < 0 || where.y >= height) {
            return false;
        }
        return !cross.contains(where) && !circle.contains(where);
    }

    public boolean canPlace(int x, int y) {
        return canPlace(new Point(x, y));
    }

    public boolean add(int player, Point where) {
        if (where.x < 0 || where.x >= width ||
                where.y < 0 || where.y >= height) {
            throw new IllegalArgumentException("where");
        }
        switch (player) {
            case CROSS:
                return cross.add(where);
            case CIRCLE:
                return circle.add(where);
            default:
                throw new IllegalArgumentException("player");
        }
    }

    public boolean add(int player, int x, int y) {
        return add(player, new Point(x, y));
    }

    public boolean addCircle(Point where) {
        return add(CIRCLE, where);
    }

    public boolean addCircle(int x, int y) {
        return add(CIRCLE, x, y);
    }

    public boolean addCross(Point where) {
        return add(CROSS, where);
    }

    public boolean addCross(int x, int y) {
        return add(CROSS, x, y);
    }

    public boolean checkCircle() {
        for (Point p: circle) {
            if (checkRow(CIRCLE, p)) {
                return true;
            }
        }

        return false;
    }

    public boolean checkCross() {
        for (Point p: cross) {
            if (checkRow(CROSS, p)) {
                return true;
            }
        }
        return false;
    }

    private boolean checkRow(int player, Point start) {
        int inARow;
        for (int i = 0; i < 8; i++) {
            inARow = 1;
            inARow += checkDirection(player, start, i);
            if (inARow > 4) {
                return true;
            }
        }
        return false;
    }

    private int checkDirection(int player, Point start, int direction) {
        Point checked = (Point)start.clone();
        switch (direction) {
            case 0:
                checked.y--; break;
            case 1:
                checked.y--;
                checked.x++; break;
            case 2:
                checked.x++; break;
            case 3:
                checked.x++;
                checked.y++; break;
            case 4:
                checked.y++; break;
            case 5:
                checked.y++;
                checked.x--; break;
            case 6:
                checked.x--; break;
            case 7:
                checked.x--;
                checked.y--; break;
            default:
                throw new IllegalArgumentException("direction");
        }
        switch (player) {
            case CROSS:
                if (cross.contains(checked)) {
                    return 1 + checkDirection(player, checked, direction);
                } else {
                    return 0;
                }
            case CIRCLE:
                if (circle.contains(checked)) {
                    return 1 + checkDirection(player, checked, direction);
                } else {
                    return 0;
                }
            default:
                throw new IllegalArgumentException("player");
        }
    }

    @Override
    public Object clone() {
        Object res = null;
        try {
            res = super.clone();
        } catch (CloneNotSupportedException ex) {
            //impossible
            Logger.getLogger(Desk.class.getName()).log(Level.SEVERE, null, ex);
        }

        return res;
    }
}
